using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace OpenComposite.Base.Designer
{
	[ToolboxBitmap(typeof(UserControl))]
	public partial class DesignerViewControl : UserControl, IServiceProvider
	{
		#region Initialization
		public DesignerViewControl()
		{
			InitializeComponent();
			
			init();
		}
		private void init()
		{
			_dropTypes = new List<Type>();
			_designerControls = new DesignerViewControlCollection(this);
			_selectedItems = new SelectedDesignerControlCollection(this);
			_gridSize = new Size(10, 10);


			// Set style to avoid flickering.
			SetStyle(ControlStyles.OptimizedDoubleBuffer |
					 ControlStyles.AllPaintingInWmPaint |
					 ControlStyles.UserPaint, true);
			UpdateStyles();

			vScrollBar.Scroll += new ScrollEventHandler(vScrollBar_Scroll);
			hScrollBar.Scroll += new ScrollEventHandler(hScrollBar_Scroll);

			pnlViewArea.Resize += new EventHandler(pnlViewArea_Resize);

			pnlMain.Resize += new EventHandler(pnlMain_Resize);
			pnlMain.Paint += new PaintEventHandler(pnlMain_Paint);
			pnlMain.MouseMove += new MouseEventHandler(pnlMain_MouseMove);
			pnlMain.MouseDown += new MouseEventHandler(pnlMain_MouseDown);
			pnlMain.MouseUp += new MouseEventHandler(pnlMain_MouseUp);
			pnlMain.MouseClick += new MouseEventHandler(pnlMain_MouseClick);
			pnlMain.MouseDoubleClick += new MouseEventHandler(pnlMain_MouseDoubleClick);

			pnlMain.DragDrop += new DragEventHandler(pnlMain_DragDrop);
			pnlMain.DragEnter += new DragEventHandler(pnlMain_DragEnter);
			pnlMain.DragLeave += new EventHandler(pnlMain_DragLeave);
			pnlMain.DragOver += new DragEventHandler(pnlMain_DragOver);
			pnlMain.GiveFeedback += new GiveFeedbackEventHandler(pnlMain_GiveFeedback);
			pnlMain.QueryContinueDrag += new QueryContinueDragEventHandler(pnlMain_QueryContinueDrag);

			pnlMain.Size = new Size(5000, 5000);
			vScrollBar.Value = vScrollBar.Maximum / 2;
			hScrollBar.Value = hScrollBar.Maximum / 2;

			pnlMain.Top = -vScrollBar.Value * _scrollFactor;
			pnlMain.Left = -hScrollBar.Value * _scrollFactor;

			IsInformationVisible = false;

			this.CursorChanged += new EventHandler(DesignerViewControl_CursorChanged);
		}

		#endregion

		#region Public Members

		#region Properties

		public IDesignController DesignController
		{
			get { return _designController; }
			set {
				if ( _designController != value ) {
					_designController = value;
					doDesignControllerChanged();
				}
			}
		}

		public DesignerControl MainControl
		{
			get { return _mainCtrl; }
			set { _mainCtrl = value; }
		}
		public DesignerViewControlCollection DesignerControls
		{
			get { return _designerControls; }
		}

		public Size GridSize
		{
			get { return _gridSize; }
			set
			{
				_gridSize = value;
				doGridSizeChanged();
			}
		}

		public bool MultiSelect
		{
			get
			{
				return _selectedItems.MultiSelect;
			}
			set
			{
				_selectedItems.MultiSelect = value;
			}
		}

		public SelectedDesignerControlCollection SelectedControls
		{
			get { return _selectedItems; }
		}

		public DesignerViewPanel MainPanel
		{
			get { return pnlMain; }
		}
		public ControlCollection ViewControls
		{
			get { return this.pnlMain.Controls; }
		}

		public Type[] Types
		{
			get { return _types; }
			set { _types = value; }
		}
		public List<Type> DropTypes
		{
			get { return _dropTypes; }
		}

		public ContextMenuStrip MainContextMenuStrip
		{
			get { return contextMain; }
		}

		public float ZoomFactor
		{
			get { return _zoom; }
			set
			{
				if ( _zoom != value )
					zoom(value);
			}
		}

		public bool IsInformationVisible
		{
			get { return lblInformations.Visible; }
			set { lblInformations.Visible = value; }
		}

		public ISite DesignerSite
		{
			get { return _designerSite; }
			set {
				if ( _designerSite != value ) {
					_designerSite = value;
					foreach ( DesignerControl dc in this.DesignerControls ) {
						dc.Site = _designerSite;
					}
				}
			}
		}

		public ScrollBars ScrollBars
		{
			get { return _scrollbars; }
			set {
				switch ( value ) {
					case ScrollBars.Both:
						pnlVScroll.Visible = true;
						hScrollBar.Visible = true;
						break;
					case ScrollBars.Horizontal:
						pnlVScroll.Visible = false;
						hScrollBar.Visible = true;
						break;
					case ScrollBars.None:
						pnlVScroll.Visible = false;
						hScrollBar.Visible = false;
						break;
					case ScrollBars.Vertical:
						pnlVScroll.Visible = true;
						hScrollBar.Visible = false;
						break;
					default:
						break;
				};
			}
		}

		public bool ReadOnly
		{
			get { return _readOnly; }
			set
			{
				_readOnly = value;
				//base.Enabled = !value;
				this.MainPanel.Enabled = !value;
				//pnlVScroll.Enabled = value;
				//hScrollBar.Enabled = value;
				OnReadOnlyChanged(EventArgs.Empty);
			}
		}

		public Point ViewPosition
		{
			get { return getViewPosition(); }
			set { setViewPosition(value); }
		}

		private volatile Cursor _referenceCursor = null;
		public override Cursor Cursor
		{
			get
			{
				return base.Cursor;
			}
			set
			{
				if ( value != _referenceCursor || this.Status.CurrentMouseMoveMode != MouseMoveMode.DragDrop ) {
					_referenceCursor = value;
					base.Cursor = value;
				}
			}
		}

		public ToolTip ToolTip
		{
			get { return this.toolTip; }
		}
		public void SetToolText(string value)
		{
			if ( ToolTip.GetToolTip(pnlMain) != value )
				ToolTip.SetToolTip(pnlMain, value);
		}
		#endregion

		#region Events

		public event EventHandler GridSizeChanged = null;
		public event EventHandler ReadOnlyChanged = null;
		public new event MouseEventHandler MouseMove = null;
		public new event MouseEventHandler MouseDown = null;
		public new event MouseEventHandler MouseUp = null;
		public new event MouseEventHandler MouseClick = null;
		public new event MouseEventHandler MouseDoubleClick = null;

		#endregion

		#region Methods

		public override void Refresh()
		{
			if ( _iSuspendCount > 0 )
				return;

			if ( pnlMain.InvokeRequired )
				pnlMain.Invoke(new MethodInvoker(pnlMain.Refresh));
			else
				pnlMain.Update();
		}
		
		public void DropObject(object obj, Point location, MouseButtons button)
		{
			DesignerControl dc = GetDesignerControlAt(location);
			if ( dc != null ) {
				dc.DropObject(obj, location, button);
			} else if ( this.DropTypes.Contains(obj.GetType()) ) {
				this.AddDesignerControl((DesignerControl)obj);
			}
		}
		public bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			DesignerControl dc = GetDesignerControlAt(location);
			this.Status.MouseOverCtrl = dc;
			if ( dc != null ) {
				return dc.IsDropAllowed(obj, location, button);
			} else {
				return this.DropTypes.Contains(obj.GetType());
			}
		}
		public bool IsDropAllowed(Type type, Point location, MouseButtons button)
		{
			if ( !type.IsSubclassOf(typeof(DesignerControl)) && type != typeof(DesignerControl) )
				return false;
			DesignerControl dc = GetDesignerControlAt(location);
			this.Status.MouseOverCtrl = dc;
			if ( dc != null ) {
				// TODO: add function IsDropAllowed(Type type,..) to the DesignerControl base class and
				// implement an override in all derrifed classes
				return dc.IsDropAllowed(type, location, button);
			} else {
				return this.DropTypes.Contains(type);
			}
		}

		public int AddDesignerControl(DesignerControl control)
		{
			return this.DesignerControls.Add(control);
		}

		public Route AddRoute(DesignerControl start, DesignerControl end)
		{
			// check for existing routes
			//foreach ( DesignerControl dc in this.DesignerControls ) {
			//    if ( dc is Route && dc == dc ) {
			//        return (Route)dc;
			//    }
			//}
			// create new route
			Route r = this.DesignController.CreateNewRoute(start, end);//new Route();
			r.ConnectDesignerControls(start, end);
			AddDesignerControl(r);
			r.Invalidate();
			r.Update();
			return r;
		}
		/// <summary>
		/// Removes the routes between the start and end control.
		/// </summary>
		/// <param name="start">The start control of the route.</param>
		/// <param name="end">The end control of the route.</param>
		/// <returns>Returns <c>true</c> if a route was removed or <c>false</c> if no route was removed or no route exists between the controls.</returns>
		public bool RemoveRoute(DesignerControl start, DesignerControl end)
		{
			bool routeRemoved = false;
			// check for existing routes
			List<Route> lstRemove = new List<Route>();
			foreach ( DesignerControl dc in this.DesignerControls ) {
				if ( dc is Route && ( (Route)dc ).StartControl == start && ( (Route)dc ).EndControl == end ) {
					lstRemove.Add((Route)dc);
				}
			}
			foreach ( Route route in lstRemove ) {
				route.Invalidate();
				route.Remove();
				routeRemoved = true;
			}
			return routeRemoved;
		}
		public Route[] GetRoutesStartToEnd(DesignerControl start)
		{
			List<Route> routes = new List<Route>();
			foreach ( DesignerControl dc in this.DesignerControls ) {
				if ( dc is Route && ( (Route)dc ).StartControl == start )
					routes.Add((Route)dc);
			}
			return routes.ToArray();
		}
		public Route[] GetRoutesEndToStart(DesignerControl end)
		{
			List<Route> routes = new List<Route>();
			foreach ( DesignerControl dc in this.DesignerControls ) {
				if ( dc is Route && ( (Route)dc ).EndControl == end )
					routes.Add((Route)dc);
			}
			return routes.ToArray();
		}

		public new Point PointToClient(Point p)
		{
			return this.pnlMain.PointToClient(p);
		}
		public new Point PointToScreen(Point p)
		{
			return this.pnlMain.PointToScreen(p);
		}

		public XmlDocument SaveDiagramToXml(Type[] additionalTypes)
		{
			_types = additionalTypes;
			XmlDocument xd = new XmlDocument();
			XmlNode xnDiagram = xd.AppendChild(xd.CreateElement("DesignerDiagram"));
			XmlAttribute xaPos = xnDiagram.Attributes.Append(xd.CreateAttribute("ViewPosition"));
			xaPos.Value = new PointConverter().ConvertToString(null,
				System.Globalization.CultureInfo.InvariantCulture, getViewPosition());

			XmlNode xnControls = xd.DocumentElement.AppendChild(xd.CreateElement("DesignerControls"));
			XmlNode xnRoutes = xd.DocumentElement.AppendChild(xd.CreateElement("Routes"));

			XmlSerializer xs = new XmlSerializer(typeof(DesignerControl), additionalTypes);
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = false;
			settings.NewLineChars = string.Empty;
			settings.OmitXmlDeclaration = true;

			foreach ( DesignerControl dc in this.DesignerControls ) {
				using ( StringWriter sw = new StringWriter() )
				using ( XmlWriter xw = XmlWriter.Create(sw, settings) ) {
					xs.Serialize(xw, dc);
					xw.Flush();
					XmlDocument x = new XmlDocument();
					x.LoadXml(sw.ToString());
					if ( x.DocumentElement.HasChildNodes ) {
						if ( dc is Route )
							xnRoutes.AppendChild(xd.ImportNode(x.DocumentElement, true));
						else
							xnControls.AppendChild(xd.ImportNode(x.DocumentElement, true));
					}
				}
			}
			return xd;
		}
		public void LoadDiagramFromXml(XmlDocument xd, Type[] additionalTypes)
		{
			if ( xd == null )
				return;
			this.BeginUpdate();
			_types = additionalTypes;
			XmlSerializer xs = new XmlSerializer(typeof(DesignerControl), additionalTypes);
			XmlNodeList xnlControls = xd.SelectNodes("/DesignerDiagram/DesignerControls/DesignerControl");
			XmlNodeList xnlRoutes = xd.SelectNodes("/DesignerDiagram/Routes/DesignerControl");
			XmlAttribute xaPos = xd.DocumentElement.Attributes["ViewPosition"];
			Point ptPos = new Point(-1, -1);
			if ( xaPos != null && xaPos.Value != "" )
				ptPos = (Point)new PointConverter().ConvertFromString(null,
					System.Globalization.CultureInfo.InvariantCulture, xaPos.Value.Replace(';',','));
			foreach ( XmlNode xn in xnlControls ) {
				// create designer control and add to DesignerControls collection
				addSerializedDesignerControl(additionalTypes, xn);
			}
			foreach ( XmlNode xn in xnlRoutes ) {
				// add route
				addSerializedDesignerControl(additionalTypes, xn);
			}
			if ( ptPos.X != -1 )
				setViewPosition(ptPos);
			this.EndUpdate();
		}
		public List<DesignerControl> LoadDiagramFromXmlAndGetTopControls(XmlDocument xd, Type[] additionalTypes)
		{
			List<DesignerControl> lstDCtrls = new List<DesignerControl>();
			if ( xd == null )
				return lstDCtrls;
			this.BeginUpdate();
			DesignerControl dctrlMain = this.MainControl;
			_types = additionalTypes;
			XmlSerializer xs = new XmlSerializer(typeof(DesignerControl), additionalTypes);
			XmlNodeList xnlControls = xd.SelectNodes("/DesignerDiagram/DesignerControls/DesignerControl");
			XmlNodeList xnlRoutes = xd.SelectNodes("/DesignerDiagram/Routes/DesignerControl");
			XmlAttribute xaPos = xd.DocumentElement.Attributes["ViewPosition"];
			Point ptPos = new Point(-1, -1);
			if ( xaPos != null && xaPos.Value != "" )
				ptPos = (Point)new PointConverter().ConvertFromString(xaPos.Value);
			foreach ( XmlNode xn in xnlControls ) {
				// create designer control and add to DesignerControls collection
				DesignerControl dctrl = addSerializedDesignerControl(additionalTypes, xn);
				if ( dctrl != null )
					lstDCtrls.Add(dctrl);
			}
			foreach ( XmlNode xn in xnlRoutes ) {
				// add route
				addSerializedDesignerControl(additionalTypes, xn);
			}
			//if ( ptPos.X != -1 )
			//    setViewPosition(ptPos);

			this.MainControl = dctrlMain;
			this.EndUpdate();
			return lstDCtrls;
		}
		public List<DesignerControl> LoadDiagramFromXmlAndGetTopControlsHierarchyOnly(XmlDocument xd, Type[] additionalTypes)
		{
			List<DesignerControl> lstDCtrls = new List<DesignerControl>();
			if ( xd == null )
				return lstDCtrls;
			this.BeginUpdate();
			DesignerControl dctrlMain = this.MainControl;
			_types = additionalTypes;
			XmlSerializer xs = new XmlSerializer(typeof(DesignerControl), additionalTypes);
			XmlNodeList xnlControls = xd.SelectNodes("/DesignerDiagram/DesignerControls/DesignerControl");
			XmlNodeList xnlRoutes = xd.SelectNodes("/DesignerDiagram/Routes/DesignerControl");
			XmlAttribute xaPos = xd.DocumentElement.Attributes["ViewPosition"];
			Point ptPos = new Point(-1, -1);
			if ( xaPos != null && xaPos.Value != "" )
				ptPos = (Point)new PointConverter().ConvertFromString(null, System.Globalization.CultureInfo.InvariantCulture,
					xaPos.Value.Replace(';', ','));
			foreach ( XmlNode xn in xnlControls ) {
				// create designer control and add to DesignerControls collection
				DesignerControl dctrl = null;
				try {
					dctrl = getSerializedDesignerControl(additionalTypes, xn);
				} catch {
					dctrl = null;
				}
				if ( dctrl != null )
					lstDCtrls.Add(dctrl);
			}
			foreach ( XmlNode xn in xnlRoutes ) {
				// add route
				getSerializedDesignerControl(additionalTypes, xn);
			}
			//if ( ptPos.X != -1 )
			//    setViewPosition(ptPos);

			//this.MainControl = dctrlMain;
			this.EndUpdate();
			return lstDCtrls;
		}

		public void BeginUpdate()
		{
			lock ( lockThis )
				_iSuspendCount++;
		}
		public void EndUpdate()
		{
			lock ( lockThis ) {
				//if ( _iSuspendCount > 0 )
				_iSuspendCount--;
				if ( _iSuspendCount <= 0 ) {
					_iSuspendCount = 0;
					this.Refresh();
				}
			}
		}

		public DesignerControl FindControl(Guid id)
		{
			foreach ( DesignerControl ctrl in this.DesignerControls ) {
				if ( ctrl.Identifier == id )
					return ctrl;
				DesignerControl c = findControlRecursive(ctrl, id);
				if ( c != null )
					return c;
			}
			return null;
		}
		public DesignerControl GetDesignerControlAt(Point location)
		{
			DesignerControl current = null;
			foreach ( DesignerControl dcSel in this.SelectedControls ) {
				if ( dcSel.SelectionFrame != null && dcSel.SelectionFrame.CheckMouseOver(location) )
					return dcSel;
			}
			for ( int i = this.DesignerControls.Routes.Count - 1; i >= 0; i-- ) {
				current = this.DesignerControls.Routes[i];
				if ( current.CheckMouseOver(location) ) {
					return current;
				}
			}
			for ( int i = this.DesignerControls.ControlsWithoutRoutes.Count - 1; i >= 0; i-- ) {
				current = this.DesignerControls.ControlsWithoutRoutes[i];
				if ( current.CheckMouseOver(location) ) {
					return current.GetTopMostChildAtDesignerViewPoint(location);
				}
			}
			if ( this.Status.MouseOverCtrl != null && this.Status.MouseOverCtrl.CheckMouseOver(location) ) {
				return this.Status.MouseOverCtrl.GetTopMostChildAtDesignerViewPoint(location);
			}
			return null;
		}
		public void CalculateMouseOverControl(Point location)
		{
			DesignerControl dc = this.GetDesignerControlAt(location);
			this.Status.MouseOverCtrl = dc;
		}

		public Point PointToGrid(Point p)
		{
			return new Point(p.X - p.X % this.GridSize.Width, p.Y - p.Y % this.GridSize.Height);
		}
		public Size SizeToGrid(Size s)
		{
			return new Size(s.Width - s.Width % this.GridSize.Width, s.Height - s.Height % this.GridSize.Height);
		}
		public Rectangle RectangleToGrid(Rectangle r)
		{
			return new Rectangle(r.X - r.X % this.GridSize.Width, r.Y - r.Y % this.GridSize.Height,
				r.Width - r.Width % this.GridSize.Width, r.Height - r.Height % this.GridSize.Height);
		}

		public void SaveAsImage()
		{
			saveImageDlg.FileName = "Diagram_" + DateTime.Now.ToString("yyyyMMdd_HHmm");
			if ( saveImageDlg.ShowDialog() == DialogResult.OK ) {
				this.Refresh();
				Rectangle bounds = getPrintingBounds();
				bounds.Inflate(12, 12);
				Bitmap bmpView = new Bitmap(bounds.Width, bounds.Height);
				try {
					//using ( Graphics g = Graphics.FromImage(bmpView) )
					//using ( PaintEventArgs pe = new PaintEventArgs(g, bounds) ) {
					//    enableHighQualityRendering(pe);
					//    paintDesignerControls(pe);
					//}
					using ( Bitmap bmpAll = new Bitmap(pnlMain.Width, pnlMain.Height) ) {
						pnlMain.DrawToBitmap(bmpAll, new Rectangle(0, 0, pnlMain.Width, pnlMain.Height));
						bmpView = bmpAll.Clone(bounds, System.Drawing.Imaging.PixelFormat.DontCare);
					}
					if ( bmpView == null )
						MessageBox.Show("Could not save empty image.", "Save Image Failed.", MessageBoxButtons.OK, MessageBoxIcon.Error);
					else
						bmpView.Save(saveImageDlg.FileName);
				} catch ( Exception ex ) {
					MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
				} finally {
					if ( bmpView != null ) {
						bmpView.Dispose();
						bmpView = null;
						GC.Collect();
					}
				}
			}
		}

		public void Print()
		{
			this.Refresh();
			if ( printDlg.ShowDialog() == DialogResult.OK )
				printDoc.Print();
		}
		public void PrintSetup()
		{
			this.Refresh();
			printPageSetup.ShowDialog();
		}
		public void PrintPreview()
		{
			this.Refresh();
			printPreviewDlg.ShowDialog();
		}

		public Point ApplyZoomFactor(Point p)
		{
			Point point;
			float zoom = this.ZoomFactor;
			if ( zoom != 1.0f )
				point = new Point((int)( p.X / zoom ), (int)( p.Y / zoom ));
			else
				point = p;
			return point;
		}
		public Rectangle ApplyZoomFactor(Rectangle r)
		{
			Rectangle rect;
			float zoom = this.ZoomFactor;
			if ( zoom != 1.0f )
				rect = new Rectangle((int)( r.X / zoom ), (int)( r.Y / zoom ), (int)( r.Width / zoom ), (int)( r.Height / zoom ));
			else
				rect = r;
			return rect;
		}

		public void SetHScrollbarValue(int value)
		{
			hScrollBar.Value = value;
		}

		public void SetVScrollbarValue(int value) {
			vScrollBar.Value = value;
		}

		#region IServiceProvider Members

		public new object GetService(Type serviceType)
		{
			if ( this.DesignerSite != null )
				return this.DesignerSite.GetService(serviceType);
			else if ( this.Site != null )
				return this.Site.GetService(serviceType);
			else
				return null;
		}

		#endregion

		#endregion

		#endregion

		#region Internal Members

		#region Variables
		internal DesignerStatus Status
		{
			get { return _status; }
		}
		private volatile DesignerStatus _status = new DesignerStatus();
		#endregion

		#endregion

		#region Protected Members

		#region Locking
		protected object lockThis = new object();
		protected static object lockAll = new object();
		#endregion

		#region Overrided Methods

		protected override bool IsInputKey(Keys keyData)
		{
			return base.IsInputKey(keyData);
		}
		protected override bool ProcessDialogKey(Keys keyData)
		{
			if ( this.SelectedControls.Count > 0 ) {
				if ( this.Status.ActiveTextBox != null ) {
					return base.ProcessDialogKey(keyData);
					// EXIT
				}
				Size szMove = new Size();
				if ( keyData == Keys.Delete ) {
					for ( int i = 0; i < this.SelectedControls.Count; i++ ) {
						this.SelectedControls[i].Remove();
					}
				}
				Keys modifiers = keyData;
				if ( Form.ModifierKeys != Keys.None ) {
					modifiers = ~Keys.Modifiers & keyData;
				}
				if ( modifiers == Keys.Up ) szMove.Height = -this.GridSize.Height;
				if ( modifiers == Keys.Down ) szMove.Height = this.GridSize.Height;
				if ( modifiers == Keys.Left ) szMove.Width = -this.GridSize.Width;
				if ( modifiers == Keys.Right ) szMove.Width = this.GridSize.Width;
				foreach ( DesignerControl ctrl in this.SelectedControls.ToArray() ) {
					if ( !ctrl.CanMove )
						continue;
					if ( szMove.Height != 0 ) ctrl.Top += szMove.Height;
					if ( szMove.Width != 0 ) ctrl.Left += szMove.Width;
				}
			}
			return base.ProcessDialogKey(keyData);
		}
		protected override void OnMouseWheel(MouseEventArgs e)
		{
			int delta = vScrollBar.SmallChange * e.Delta * SystemInformation.MouseWheelScrollLines / 120;
			if ( ( ModifierKeys & Keys.Shift ) != 0 ) {
				int x = hScrollBar.Value - delta;

				if ( x < hScrollBar.Minimum )
					x = hScrollBar.Minimum;
				else if ( x > hScrollBar.Maximum )
					x = hScrollBar.Maximum;

				hScrollBar.Value = x;
				pnlMain.Left = -hScrollBar.Value * _scrollFactor;
			} else {
				int y = vScrollBar.Value - delta;

				if ( y < vScrollBar.Minimum )
					y = vScrollBar.Minimum;
				else if ( y > vScrollBar.Maximum )
					y = vScrollBar.Maximum;

				vScrollBar.Value = y;
				pnlMain.Top = -vScrollBar.Value * _scrollFactor;
			}
		}
		protected override void OnLocationChanged(EventArgs e)
		{
			base.OnLocationChanged(e);
		}

		#endregion

		#region Methods

		protected virtual void OnGridSizeChanged(EventArgs e)
		{
			EventHandler tmp = this.GridSizeChanged;
			if ( tmp != null )
				tmp(this, e);
		}

		protected virtual string GetInformationText()
		{
			if ( !lblInformations.Visible )
				return "";
			Point loc = this.PointToClient(Cursor.Position);
			return string.Format(
				"Mouse Position: X = {0} ; Y = {1}{2}" +
				"Mouse View Location: X = {7} ; Y = {8}{2}" +
				"MouseOver: {3} typeof: {9}{2}" +
				"Capture: {4} typeof: {10}{2}" +
				"Focus: {5} typeof: {11}{2}" +
				"Drag: {6} typeof: {12}",
				Cursor.Position.X, Cursor.Position.Y, Environment.NewLine, this.Status.MouseOverCtrl,
				this.Status.CaptureControl, this.Status.FocusedContol, this.Status.DragObject, loc.X, loc.Y,
				this.Status.MouseOverCtrl == null ? "null" : this.Status.MouseOverCtrl.GetType().ToString(),
				this.Status.CaptureControl == null ? "null" : this.Status.CaptureControl.GetType().ToString(),
				this.Status.FocusedContol == null ? "null" : this.Status.FocusedContol.GetType().ToString(),
				this.Status.DragObject == null ? "null" : this.Status.DragObject.GetType().ToString()); ;
		}

		protected virtual void OnReadOnlyChanged(EventArgs e)
		{
			EventHandler tmp = this.ReadOnlyChanged;
			if ( tmp != null ) {
				tmp(this, e);
			}
		}

		#endregion

		#endregion

		#region Private Members

		#region Variables
		private int _iSuspendCount = 0;

		private volatile Type[] _types;
		private volatile List<Type> _dropTypes;
		private volatile DesignerControl _mainCtrl;
		private volatile DesignerViewControlCollection _designerControls = null;

		private volatile SelectedDesignerControlCollection _selectedItems;

		private volatile IDesignController _designController = null;
		private ScrollBars _scrollbars = ScrollBars.Both;
		private bool _readOnly = false;

		private float _zoom = 1.0f;
		private int _scrollFactor = 5;
		private Size _gridSize;

		private int _timerScrollSpeedup;
		//private RectangleF _rectfInformations = new RectangleF();

		private ISite _designerSite;
		
		//private UserActivityHook _mouseHook = null;

		#endregion

		#region Methods

		private void adaptScrollbars()
		{
			int ch = pnlMain.Height, cw = pnlMain.Width;
			int ph = pnlViewArea.Height, pw = pnlViewArea.Width;

			if ( ch > ph )
				vScrollBar.Maximum = ( ch - ph ) / _scrollFactor + vScrollBar.LargeChange;
			else
				vScrollBar.Maximum = vScrollBar.Minimum;

			if ( vScrollBar.Value > vScrollBar.Maximum )
				vScrollBar.Value = vScrollBar.Maximum;

			if ( cw > pw )
				hScrollBar.Maximum = ( cw - pw ) / _scrollFactor + hScrollBar.LargeChange;
			else
				hScrollBar.Maximum = hScrollBar.Minimum;

			if ( hScrollBar.Value > hScrollBar.Maximum )
				hScrollBar.Value = hScrollBar.Maximum;
		}
		private void doGridSizeChanged()
		{
			OnGridSizeChanged(new EventArgs());
			this.Refresh();
		}

		private void doDesignControllerChanged()
		{
			if ( _designController.AdditionalContextMenuStrip != null ) {
				ToolStripItemCollection items = _designController.AdditionalContextMenuStrip.Items;
				int i = 0;
				while ( i < items.Count ) {
					this.pnlMain.ContextMenuStrip.Items.Insert(i, items[i]);
					i++;
				}
				this.MainPanel.ContextMenuStrip.Items.Insert(i + 1, new ToolStripSeparator());
			}
		}

		private DesignerControl addSerializedDesignerControl(Type[] additionalTypes, XmlNode xn)
		{
			DesignerControl dctrl = null;
			Type type = null;
			try {
				foreach ( Type t in additionalTypes ) {
					if ( t.FullName == xn.Attributes["Type"].Value ) {
						type = t;
						break;
					}
				}
				if ( type == null )
					type = Type.GetType(xn.Attributes["Type"].Value);
			} catch {
				type = null;
			}
			if ( type != null ) {
				System.Reflection.ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
				object obj = ctor.Invoke(new object[0]);
				if ( obj is IXmlSerializable ) {
					if ( obj is DesignerControl ) {
						this.AddDesignerControl((DesignerControl)obj);
						dctrl = (DesignerControl)obj;
					}
					try {
						( (IXmlSerializable)obj ).ReadXml(new XmlNodeReader(xn));
						if ( obj is DesignerControl ) {
							( (DesignerControl)obj ).InitializeLoaded();
						}
					} catch {
						if ( dctrl != null ) {
							this.DesignerControls.Remove(dctrl);
							dctrl = null;
						}
					}
				}
			}
			return dctrl;
		}
		private DesignerControl getSerializedDesignerControl(Type[] additionalTypes, XmlNode xn)
		{
			DesignerControl dctrl = null;
			Type type = null;
			try {
				foreach ( Type t in additionalTypes ) {
					if ( t.FullName == xn.Attributes["Type"].Value ) {
						type = t;
						break;
					}
				}
				if ( type == null )
					type = Type.GetType(xn.Attributes["Type"].Value);
			} catch {
				type = null;
			}
			if ( type != null ) {
				System.Reflection.ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
				object obj = ctor.Invoke(new object[0]);
				if ( obj is IXmlSerializable ) {
					if ( obj is DesignerControl ) {
						dctrl = (DesignerControl)obj;
						dctrl.Site = this.DesignerSite;
					}
					( (IXmlSerializable)obj ).ReadXml(new XmlNodeReader(xn));
					//if ( obj is DesignerControl ) {
					//    ( (DesignerControl)obj ).InitializeLoaded();
					//}
				}
			}
			return dctrl;
		}

		private Point getViewPosition()
		{
			return new Point(-pnlMain.Left, -pnlMain.Top);
		}
		private void setViewPosition(Point pt)
		{
			pnlMain.Top = -pt.Y;
			pnlMain.Left = -pt.X;
			vScrollBar.Value = (int)( pt.Y / _scrollFactor );
			hScrollBar.Value = (int)( pt.X / _scrollFactor );
		}

		private DesignerControl findControlRecursive(DesignerControl parentctrl, Guid id)
		{
			foreach ( DesignerControl ctrl in parentctrl.Controls ) {
				if ( ctrl.Identifier == id )
					return ctrl;
				else {
					DesignerControl dc = findControlRecursive(ctrl, id);
					if ( dc != null )
						return dc;
				}
			}
			return null;
		}

		private Rectangle getPrintingBounds()
		{
			Rectangle bounds = Rectangle.Empty;
			foreach ( DesignerControl dc in this.DesignerControls ) {
				if ( dc.Visible ) {
					if ( bounds == Rectangle.Empty )
						bounds = dc.Bounds;
					else
						bounds = Rectangle.Union(bounds, dc.Bounds);
				}
			}
			return bounds;
		}

		private MouseEventArgs applyZoomFactor(MouseEventArgs e)
		{
			MouseEventArgs newMEA;
			float zoom = this.ZoomFactor;
			if ( zoom != 1.0f )
				newMEA = new MouseEventArgs(e.Button, e.Clicks, (int)Math.Floor(e.X / zoom), (int)Math.Floor(e.Y / zoom), e.Delta);
			else
				newMEA = e;
			return newMEA;
		}

		#endregion

		#region Event Handlers

		private void vScrollBar_Scroll(object sender, ScrollEventArgs e)
		{
			if ( pnlMain.Height <= pnlViewArea.Height )
				e.NewValue = 0;

			pnlMain.Top = -e.NewValue * _scrollFactor;
		}
		private void hScrollBar_Scroll(object sender, ScrollEventArgs e)
		{
			if ( pnlMain.Width <= pnlViewArea.Width )
				e.NewValue = 0;

			pnlMain.Left = -e.NewValue * _scrollFactor;
		}

		private void pnlViewArea_Resize(object sender, EventArgs e)
		{
			adaptScrollbars();
		}

		private void pnlMain_Resize(object sender, EventArgs e)
		{
			adaptScrollbars();
		}
		private void pnlMain_Paint(object sender, PaintEventArgs e)
		{
			if ( _iSuspendCount > 0 ) {
				this.MainPanel.Invalidate(e.Graphics.Clip, true);
				return;
			}
			setZoomFactor(e);

			enableHighQualityRendering(e);

			paintDesignerControls(e);
			paintSelectionFrames(e);
			paintDragObject(e);
		}

		private void setZoomFactor(PaintEventArgs e)
		{
			System.Drawing.Drawing2D.Matrix m = new System.Drawing.Drawing2D.Matrix();
			m.Scale(this.ZoomFactor, this.ZoomFactor);
			e.Graphics.Transform = m;

		}
		private void enableHighQualityRendering(PaintEventArgs e)
		{
			// enable HighQuality rendering
			e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
			e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
			e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
		}
		private void paintDesignerControls(PaintEventArgs e)
		{
			// create list of selected controls
			List<Route> listRoutes = new List<Route>();
			List<DesignerControl> listTopLevel = new List<DesignerControl>();
			List<SelectionFrame> listSelection = new List<SelectionFrame>();
			// paint child controls
			foreach ( DesignerControl ctrl in this.DesignerControls ) {
				//if ( ctrl.Bounds.IntersectsWith(Rectangle.Ceiling(e.Graphics.ClipBounds)) ) {
				if ( ctrl is Route ) {
					listRoutes.Add((Route)ctrl);
				} else if ( ctrl.TopLevel ) {
					listTopLevel.Add(ctrl);
				} else {
					Rectangle bounds = ctrl.Bounds;
					bounds.Inflate(5, 5);
					if ( e.Graphics.Clip.IsVisible(bounds) ) {
						ctrl.PaintBackground(e);
					}
					ctrl.Paint(e);
				}
			}
			// paint routes
			foreach ( Route route in listRoutes ) {
				if ( route.Bounds.IntersectsWith(Rectangle.Ceiling(e.Graphics.ClipBounds)) &&
					 route.StartControl.Visible && route.EndControl.Visible )
					route.Paint(e);
			}
			// paint top level
			foreach ( DesignerControl ctrl in listTopLevel ) {
				Rectangle bounds = ctrl.Bounds;
				bounds.Inflate(5, 5);
				if ( e.Graphics.Clip.IsVisible(bounds) ) {
					ctrl.PaintBackground(e);
				}
				ctrl.Paint(e);
			}
		}
		private void paintSelectionFrames(PaintEventArgs e)
		{
			// paint selection frames
			foreach ( DesignerControl selctrl in this.SelectedControls ) {
				if ( selctrl.SelectionFrame != null )
					selctrl.SelectionFrame.Paint(e);
			}
		}
		private void paintDragObject(PaintEventArgs e)
		{
			//if ( this.Status.DragObject != null && this.Status.CurrentMouseMoveMode == MouseMoveMode.DragDrop ) {
			//    System.Drawing.Drawing2D.Matrix m1 = new System.Drawing.Drawing2D.Matrix();
			//    m1.Scale(1f, 1f);
			//    e.Graphics.Transform = m1;
			//    string txt = ( this.Status.DragObject is DesignerControl ?
			//        ( (DesignerControl)this.Status.DragObject ).Text : this.Status.DragObject.ToString() );
			//    Point pDDtxt = this.MainPanel.PointToClient(Cursor.Position) + new Size(20, 20);
			//    e.Graphics.DrawString(txt, this.Font, Brushes.Black, pDDtxt);
			//}
		}

		private void pnlMain_MouseMove(object sender, MouseEventArgs e)
		{
			e = applyZoomFactor(e);
			Rectangle rect = pnlViewArea.Parent.RectangleToScreen(pnlViewArea.Bounds);
			Point pos = Cursor.Position;
			rect.Inflate(-5, -5);

			if ( rect.Contains(pos) && timerScroll.Enabled ) {
				timerScroll.Stop();
			} else if ( e.Button != MouseButtons.None && !timerScroll.Enabled && !rect.Contains(pos) ) {
				_timerScrollSpeedup = 0;
				timerScroll.Start();
			}
			lblInformations.Text = GetInformationText();

			if ( this.Status.CaptureControl != null ) {
				// invoke mouse move at mouse capture control
				this.Status.CaptureControl.InvokeMouseMove(e);
			} else if ( this.Status.FocusedContol != null ) {
				// invoke mouse move at mouse focused control
				this.Status.FocusedContol.InvokeMouseMove(e);
			}
			// get current mouse over control and invoke mouse move
			if ( this.Status.CurrentMouseMoveMode != MouseMoveMode.Resize ) {
				DesignerControl dc = GetDesignerControlAt(e.Location);
				if ( this.Status.MouseOverCtrl != null && this.Status.MouseOverCtrl != dc ) {
					this.Status.MouseOverCtrl.InvokeMouseLeave(e);
				}
				if ( dc != null ) {
					if ( this.Status.MouseOverCtrl != dc ) dc.InvokeMouseEnter(e);
					dc.InvokeMouseMove(e);
				}
			}
			MouseEventHandler tmp = this.MouseMove;
			if ( tmp != null ) tmp(sender, e);
		}

		private void pnlMain_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			e = applyZoomFactor(e);
			this.BeginUpdate();
			if ( this.Status.CaptureControl != null ) {
				// invoke mouse move at mouse capture control
				this.Status.CaptureControl.InvokeMouseDoubleClick(e);
			}
			// get current mouse over control and invoke mouse double click
			if ( this.Status.MouseOverCtrl != null ) {
				this.Status.MouseOverCtrl.InvokeMouseDoubleClick(e);
			}
			MouseEventHandler tmp = this.MouseDoubleClick;
			if ( tmp != null ) tmp(sender, e);

			this.EndUpdate();
		}
		private void pnlMain_MouseClick(object sender, MouseEventArgs e)
		{
			e = applyZoomFactor(e);
			this.BeginUpdate();
			if ( this.Status.CaptureControl != null ) {
				// invoke mouse click at mouse capture control
				this.Status.CaptureControl.InvokeMouseClick(e);
			}
			// get current mouse over control and invoke mouse click
			if ( this.Status.MouseOverCtrl != null &&
				 this.Status.MouseOverCtrl != this.Status.CaptureControl ) {
				this.Status.MouseOverCtrl.InvokeMouseClick(e);
			}
			MouseEventHandler tmp = this.MouseClick;
			if ( tmp != null ) tmp(sender, e);
			this.EndUpdate();
		}
		private void pnlMain_MouseUp(object sender, MouseEventArgs e)
		{
			e = applyZoomFactor(e);
			this.BeginUpdate();
			pnlMain.Capture = false;
			timerScroll.Stop();
			if ( this.Status.CaptureControl != null ) {
				// invoke mouse up at mouse capture control
				this.Status.CaptureControl.InvokeMouseUp(e);
			}
			// get current mouse over control and invoke mouse up
			if ( this.Status.MouseOverCtrl != null ) {
				this.Status.MouseOverCtrl.InvokeMouseUp(e);
			}
			if ( e.Button == MouseButtons.Right ) {
				this.MainPanel.Invalidate();
			}
			
			MouseEventHandler tmp = this.MouseUp;
			if ( tmp != null ) tmp(sender, e);
			this.EndUpdate();
		}
		private void pnlMain_MouseDown(object sender, MouseEventArgs e)
		{
			e = applyZoomFactor(e);
			this.BeginUpdate();
			pnlMain.Capture = true;
			if ( this.Status.CaptureControl != null ) {
				// invoke mouse down at mouse capture control
				this.Status.CaptureControl.InvokeMouseDown(e);
			} else
			// get current mouse over control and invoke mouse down
			if ( this.Status.MouseOverCtrl != null )
				this.Status.MouseOverCtrl.InvokeMouseDown(e);
			//}
			MouseEventHandler tmp = this.MouseDown;
			if ( tmp != null ) tmp(sender, e);

			if ( this.Status.MouseOverCtrl == null ) {
				this.Status.FocusedContol = null;
				this.SelectedControls.Clear();
			}
			this.EndUpdate();
		}

		private void pnlMain_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
		{
		}
		private void pnlMain_GiveFeedback(object sender, GiveFeedbackEventArgs e)
		{
		}
		private void pnlMain_DragOver(object sender, DragEventArgs e)
		{
			lblInformations.Text = GetInformationText();
			//if ( !e.Data.GetDataPresent(typeof(DesignerControl) ) )
			//    return;

			//DesignerControl dc = (DesignerControl)e.Data.GetData(typeof(DesignerControl));
			//if ( this.Status.MouseOverCtrl == dc ) {
			//    e.Effect = DragDropEffects.None;
			//} else if ( this.Status.MouseOverCtrl == null ) {
			//    e.Effect = DragDropEffects.Move;
			//} else {
			//    e.Effect = DragDropEffects.Link;
			//}
		}
		private void pnlMain_DragLeave(object sender, EventArgs e)
		{
		}
		private void pnlMain_DragEnter(object sender, DragEventArgs e)
		{
		}
		private void pnlMain_DragDrop(object sender, DragEventArgs e)
		{
		}

		private void pnlMain_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
		{
		}
		private void pnlMain_KeyDown(object sender, KeyEventArgs e)
		{

		}
		private void moveSelected(int dx, int dy)
		{
		}

		private void DesignerViewControl_CursorChanged(object sender, EventArgs e)
		{
			if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.DragDrop && (
						this.Status.DragDropCursor == null ||
						this.Cursor != this.Status.DragDropCursor.Cursor ) ) {
				if ( !this.Status.UseCustomCursor ) {
					string txt = this.Status.DragObject == null ? "" :
						( this.Status.DragObject is DesignerControl ?
						( (DesignerControl)this.Status.DragObject ).Text : this.Status.DragObject.ToString() );
					if ( !string.IsNullOrEmpty(txt) ) {
						this.Status.DragDropCursor = Helper.CreateDragCursor(this.Cursor, null, txt, this.Font);
						base.Cursor = this.Status.DragDropCursor.Cursor;
					}
				} else {
					if ( this.Status.DragDropCursor != null ) {
						base.Cursor = this.Status.DragDropCursor.Cursor;
					} else {
						base.Cursor = Cursors.Default;
					}
				}
			} else if ( this.Status.DragDropCursor != null && this.Cursor != this.Status.DragDropCursor.Cursor ) {
				this.Status.DragDropCursor = null;
			}
		}

		private void timerScroll_Tick(object sender, EventArgs e)
		{
			bool bChanged = false;
			int val = -1;
			int move = 5;
			Point pos = Cursor.Position;
			Rectangle rect = pnlViewArea.Parent.RectangleToScreen(pnlViewArea.Bounds);
			rect.Inflate(-5, -5);

			_timerScrollSpeedup++;
			if ( _timerScrollSpeedup > 10 )
				move *= 5;

			#region Scroll Vertical
			if ( rect.Top > pos.Y ) {
				val = vScrollBar.Value - move;
				bChanged = true;
			}
			if ( rect.Bottom < pos.Y ) {
				val = vScrollBar.Value + move;
				bChanged = true;
			}
			if ( val > vScrollBar.Maximum )
				val = vScrollBar.Maximum;
			else if ( val < vScrollBar.Minimum )
				val = vScrollBar.Minimum;
			if ( bChanged ) {
				vScrollBar.Value = val;
				pnlMain.Top = -( val * _scrollFactor );
			}
			#endregion
			val = -1;
			bChanged = false;
			#region Scroll Horizontal
			if ( rect.Left > pos.X ) {
				val = hScrollBar.Value - move;
				bChanged = true;
			}
			if ( rect.Right < pos.X ) {
				val = hScrollBar.Value + move;
				bChanged = true;
			}
			if ( val > hScrollBar.Maximum )
				val = hScrollBar.Maximum;
			else if ( val < hScrollBar.Minimum )
				val = hScrollBar.Minimum;
			if ( bChanged ) {
				hScrollBar.Value = val;
				pnlMain.Left = -( val * _scrollFactor );
			}
			#endregion
		}

		#region Main Context Menu
		private void contextMain_Opening(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if ( this.Status.MouseOverCtrl != null )
				e.Cancel = true;
		}

		#region Zoom
		private void cmiZoom25_Click(object sender, EventArgs e)
		{
			zoom(.25f);
		}
		private void cmiZoom50_Click(object sender, EventArgs e)
		{
			zoom(.5f);
		}
		private void cmiZoom75_Click(object sender, EventArgs e)
		{
			zoom(.75f);
		}
		private void cmiZoom100_Click(object sender, EventArgs e)
		{
			zoom(1.0f);
		}
		private void cmiZoom200_Click(object sender, EventArgs e)
		{
			zoom(2.0f);
		}

		private void zoom(float factor)
		{
			float old = _zoom;
			_zoom = factor;
			int vscroll = (int)( vScrollBar.Value * ( _zoom / old ) );
			int hscroll = (int)( hScrollBar.Value * ( _zoom / old ) );
			pnlMain.Scale(new SizeF(_zoom / old, _zoom / old));
			vScrollBar.Value = vscroll > vScrollBar.Maximum ? vScrollBar.Maximum : vscroll;
			hScrollBar.Value = hscroll > hScrollBar.Maximum ? hScrollBar.Maximum : hscroll;
			//try {
			//    pnlMain.Update();
			//} catch { }
		}
		#endregion

		private void cmiSaveAsImg_Click(object sender, EventArgs e)
		{
			SaveAsImage();
		}

		#region Print
		private void cmiPrint_Click(object sender, EventArgs e)
		{
			Print();
		}
		private void cmiPrintSetup_Click(object sender, EventArgs e)
		{
			PrintSetup();
		}
		private void cmiPrintPreview_Click(object sender, EventArgs e)
		{
			PrintPreview();
		}
		#endregion

		#endregion

		#region Printing

		private void printDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
		{
			Bitmap bmpView = null;
			try {
				//GraphicsUnit gp = GraphicsUnit.Point;
				Rectangle bounds = getPrintingBounds();
				bounds.Inflate(12, 12);
				bmpView = new Bitmap(bounds.Width, bounds.Height);
				using ( Bitmap bmpAll = new Bitmap(pnlMain.Width, pnlMain.Height) ) {
					pnlMain.DrawToBitmap(bmpAll, new Rectangle(0, 0, pnlMain.Width, pnlMain.Height));
					bmpView = bmpAll.Clone(bounds, System.Drawing.Imaging.PixelFormat.DontCare);
				}
				float printwidth = (float)e.MarginBounds.Width;
				float printheight = (float)e.MarginBounds.Height;
				float fZoom, fZoomW, fZoomH;
				if ( e.PageSettings.Landscape ) {
					fZoomW = printwidth / (float)bmpView.Width;
					fZoomH = printheight / (float)bmpView.Height;
				} else {
					fZoomW = printwidth / (float)bmpView.Width;
					fZoomH = printheight / (float)bmpView.Height;
				}
				fZoom = ( fZoomH < fZoomW ? fZoomH : fZoomW );
				float w = bmpView.Width * fZoom;
				float h = bmpView.Height * fZoom;
				float x = e.MarginBounds.X + ( (float)e.MarginBounds.Width / 2.0f ) - ( w / 2.0f );
				float y = e.MarginBounds.Y + ( (float)e.MarginBounds.Height / 2.0f ) - ( h / 2.0f );
				RectangleF r = new RectangleF(x, y, w, h);
				e.Graphics.DrawImage(bmpView, r);
				e.HasMorePages = false;
			} catch ( Exception ex ) {
				Debug.WriteLine(ex.Message);
			} finally {
				if ( bmpView != null ) {
					bmpView.Dispose();
					bmpView = null;
				}
				GC.Collect();
			}

		}

		#endregion

		#endregion

		#endregion

		#region Class: DesignerViewControlCollection
		public class DesignerViewControlCollection : CollectionBase
		{
			#region Initialization
			public DesignerViewControlCollection(DesignerViewControl owner)
			{
				_owner = owner;

				_controls = new List<DesignerControl>();
				_routes = new List<Route>();
			}
			#endregion

			#region Properties
			public DesignerControl this[int index]
			{
				get
				{
					return ( (DesignerControl)List[index] );
				}
				set
				{
					List[index] = value;
				}
			}

			public List<Route> Routes
			{
				get { return _routes; }
			}
			public List<DesignerControl> ControlsWithoutRoutes
			{
				get { return _controls; }
			}
			#endregion

			#region Methods
			public int Add(DesignerControl value)
			{
				// return index of existing DesignerControl
				if ( this.Contains(value) )
					return this.IndexOf(value);

				return ( List.Add(value) );
			}
			public int IndexOf(DesignerControl value)
			{
				return ( List.IndexOf(value) );
			}
			public void Insert(int index, DesignerControl value)
			{
				// if collection contains the value then first remove it from the InnerList
				// because the OnRemove is not called
				if ( InnerList.Contains(value) )
					InnerList.Remove(value);
				List.Insert(index, value);
			}
			public void Remove(DesignerControl value)
			{
				if ( List.Contains(value) )
					List.Remove(value);
			}
			public bool Contains(DesignerControl value)
			{
				// If value is not of type DesignerControl, this will return false.
				return ( List.Contains(value) );
			}
			public bool ContainsName(DesignerControl value)
			{
				if ( value != null ) {
					foreach ( DesignerControl dctrl in this._controls ) {
						if ( dctrl.Name == value.Name ) return true;
					}
				}
				return false;
			}

			public DesignerControl[] ToArray()
			{
				return (DesignerControl[])this.InnerList.ToArray(typeof(DesignerControl));
			}

			protected override void OnInsert(int index, Object value)
			{
				if ( !( value is DesignerControl ) )
					throw new ArgumentException("value must be of type DesignerControl.", "value");
			}
			protected override void OnRemove(int index, Object value)
			{
				if ( !( value is DesignerControl ) )
					throw new ArgumentException("value must be of type DesignerControl.", "value");
			}
			protected override void OnSet(int index, Object oldValue, Object newValue)
			{
				if ( !( oldValue is DesignerControl ) )
					throw new ArgumentException("oldValue must be of type DesignerControl.", "oldValue");
				if ( !( newValue is DesignerControl ) )
					throw new ArgumentException("newValue must be of type DesignerControl.", "newValue");
			}
			protected override void OnValidate(Object value)
			{
				if ( !( value is DesignerControl ) )
					throw new ArgumentException("value must be of type DesignerControl.", "value");
			}

			protected override void OnClearComplete()
			{
				refreshOwner();
				_controls.Clear();
				_routes.Clear();
				base.OnClearComplete();
			}
			protected override void OnInsertComplete(int index, object value)
			{
				DesignerControl dc = (DesignerControl)value;
				dc.Parent = null;
				dc.DesignerViewControl = _owner;
				dc.Site = _owner.DesignerSite;
				dc.Invalidate();

				refreshOwner();
				if ( value is Route )
					_routes.Add((Route)value);
				else if ( value is DesignerControl )
					_controls.Add((DesignerControl)value);

				base.OnInsertComplete(index, value);
			}
			protected override void OnRemoveComplete(int index, object value)
			{
				DesignerControl dc = (DesignerControl)value;
				//dc.Parent = null;
				//dc.DesignerViewControl = null;
				dc.Invalidate();

				refreshOwner();
				if ( value is Route )
					_routes.Remove((Route)value);
				else if ( value is DesignerControl )
					_controls.Remove((DesignerControl)value);

				base.OnRemoveComplete(index, value);
			}
			protected override void OnSetComplete(int index, object oldValue, object newValue)
			{
				DesignerControl dc;

				dc = (DesignerControl)oldValue;
				dc.Invalidate();
				//dc.Parent = null;
				//dc.DesignerViewControl = null;

				dc = (DesignerControl)newValue;
				dc.Parent = null;
				dc.DesignerViewControl = _owner;
				dc.Site = _owner.DesignerSite;
				dc.Invalidate();
				refreshOwner();

				if ( oldValue is Route )
					_routes.Remove((Route)oldValue);
				else if ( oldValue is DesignerControl )
					_controls.Remove((DesignerControl)oldValue);

				if ( newValue is Route )
					_routes.Add((Route)newValue);
				else if ( newValue is DesignerControl )
					_controls.Add((DesignerControl)newValue);

				base.OnSetComplete(index, oldValue, newValue);
			}
			private void refreshOwner()
			{
				if ( _owner != null )
					_owner.Refresh();
			}
			#endregion

			#region Private Variables

			private DesignerViewControl _owner = null;

			private List<DesignerControl> _controls;
			private List<Route> _routes;

			#endregion
		}
		#endregion

		#region Class: SelectedDesignerControlCollection
		public class SelectedDesignerControlCollection : CollectionBase
		{
			#region Initialization
			public SelectedDesignerControlCollection(DesignerViewControl owner)
			{
				_bMultiSelect = false;

				_owner = owner;
			}
			#endregion

			#region Properties
			public DesignerControl this[int index]
			{
				get
				{
					return ( (DesignerControl)List[index] );
				}
				set
				{
					List[index] = value;
				}
			}

			public bool MultiSelect
			{
				get { return _bMultiSelect; }
				set
				{
					_bMultiSelect = value;
					if ( !_bMultiSelect && List.Count > 1 ) {
						for ( int i = 1; i < List.Count; i++ ) {
							List.RemoveAt(1);
						}
					}
				}
			}

			#endregion

			#region Methods
			public int Add(DesignerControl value)
			{
				if ( !_bMultiSelect ) {
					if ( List.Count == 0 || List[0] != value ) {
						while ( List.Count > 0 )
							( (DesignerControl)List[0] ).Selected = false;
						List.Clear();
						return ( List.Add(value) );
					} else {
						return 0;
					}
				} else {
					return ( List.Add(value) );
				}
			}
			public int IndexOf(DesignerControl value)
			{
				return ( List.IndexOf(value) );
			}
			public void Insert(int index, DesignerControl value)
			{
				if ( !_bMultiSelect && index > 0 )
					throw new Exception("index > 0 in single selection mode not allowed.");

				List.Insert(index, value);
			}
			public void Remove(DesignerControl value)
			{
				if ( List.Contains(value) )
					List.Remove(value);
			}
			public bool Contains(DesignerControl value)
			{
				// If value is not of type DesignerControl, this will return false.
				return ( List.Contains(value) );
			}
			public DesignerControl[] ToArray()
			{
				DesignerControl[] controls = new DesignerControl[this.Count];
				for ( int i = 0; i < this.Count; i++ ) {
					controls[i] = this[i];
				}
				return controls;
			}

			protected override void OnClear()
			{
				while ( List.Count > 0 )
					( (DesignerControl)List[0] ).Selected = false;
			}
			protected override void OnInsert(int index, Object value)
			{
				DesignerControl dc = (DesignerControl)value;
				dc.Selected = true;
			}
			protected override void OnRemove(int index, Object value)
			{
				DesignerControl dc = (DesignerControl)value;
				dc.Selected = false;
			}
			protected override void OnSet(int index, Object oldValue, Object newValue)
			{
				DesignerControl dc = (DesignerControl)oldValue;
				dc.Selected = false;
				dc = (DesignerControl)newValue;
				dc.Selected = true;
			}
			protected override void OnValidate(Object value)
			{
				if ( !( value is DesignerControl ) )
					throw new ArgumentException("value must be of type DesignerControl.", "value");
			}

			protected override void OnClearComplete()
			{
				refreshOwner();
				base.OnClearComplete();
			}
			protected override void OnInsertComplete(int index, object value)
			{
				if ( value is DesignerControl ) {
					( (DesignerControl)value ).Refresh();
				}
				//refreshOwner();
				base.OnInsertComplete(index, value);
			}
			protected override void OnRemoveComplete(int index, object value)
			{
				if ( value is DesignerControl ) {
					( (DesignerControl)value ).Refresh();
				}
				//refreshOwner();
				base.OnRemoveComplete(index, value);
			}
			protected override void OnSetComplete(int index, object oldValue, object newValue)
			{
				refreshOwner();
				base.OnSetComplete(index, oldValue, newValue);
			}
			private void refreshOwner()
			{
				if ( _owner != null )
					_owner.Refresh();
			}
			#endregion

			#region Private Variables

			private bool _bMultiSelect;
			private DesignerViewControl _owner;

			#endregion
		}
		#endregion

		private void pnlMain_KeyUp(object sender, KeyEventArgs e)
		{
#if DEBUG
			if ( e.Control && e.Alt && e.KeyCode == Keys.I ) {
				if ( this.SelectedControls != null && this.SelectedControls.Count > 0 ) {
					EventHandler<EventArgs<object>> tmp = this.ShowDebugInfo;
					if ( tmp != null ) {
						tmp(this, new EventArgs<object>(this.SelectedControls));
					}
				} else {
					lblInformations.Visible = !lblInformations.Visible;
				}
			}
#endif
		}

		public event EventHandler<EventArgs<object>> ShowDebugInfo;
	}
	#region Class: DesignerStatus
	internal class DesignerStatus
	{
		internal DesignerControl FocusedContol
		{
			get { return _focusCtrl; }
			set
			{
				if ( _focusCtrl != value ) releaseFocus();
				_focusCtrl = value;
				setFocus();
			}
		}
		internal DesignerControl CaptureControl
		{
			get { return _captureCtrl; }
			set { _captureCtrl = value; }
		}
		internal DesignerControl MouseOverCtrl
		{
			get { return _overCtrl; }
			set {
				if ( _overCtrl != value ) {
					_overCtrl = value;
					if ( _overCtrl != null ) {
						_overCtrl.InvokeMouseEnter(EventArgs.Empty);
					}
				}
			}
		}
		internal object DragObject
		{
			get { return _dragObj; }
			set { _dragObj = value; }
		}
		internal MouseMoveMode CurrentMouseMoveMode
		{
			get { return _currentMMMode; }
			set { 
				_currentMMMode = value;
				if ( _currentMMMode != MouseMoveMode.Resize ) {
					_currentResizeState = ResizeState.None;
				}
			}
		}
		internal ResizeState CurrentResizeState
		{
			get { return _currentResizeState; }
			set { _currentResizeState = value; }
		}
		internal TextBox ActiveTextBox
		{
			get { return _activeTextBox; }
			set { _activeTextBox = value; }
		}
		internal bool IsUserResizing
		{
			get { return _isUserResizing; }
			set { _isUserResizing = value; }
		}
		internal BitmapCursor DragDropCursor {
			get { return _cursorDragDrop; }
			set
			{
				if ( _cursorDragDrop != null && _cursorDragDrop != value ) {
					_cursorDragDrop.Dispose();
				}
				_cursorDragDrop = value;
			}
		}
		internal bool UseCustomCursor { get; set; }

		private volatile DesignerControl _overCtrl = null;
		private volatile DesignerControl _focusCtrl = null;
		private volatile DesignerControl _captureCtrl = null;
		private volatile object _dragObj = null;
		private volatile MouseMoveMode _currentMMMode = MouseMoveMode.Normal;
		private volatile ResizeState _currentResizeState = ResizeState.None;
		private volatile TextBox _activeTextBox = null;
		private volatile bool _isUserResizing = false;
		private volatile BitmapCursor _cursorDragDrop = null;

		private void releaseFocus()
		{
			if ( _focusCtrl != null ) _focusCtrl.ReleaseFocus();
		}
		private void setFocus()
		{
			if ( _focusCtrl != null && !_focusCtrl.Focused ) _focusCtrl.Focus();
		}

	}
	internal enum MouseMoveMode
	{
		Normal,
		Move,
		Copy,
		Resize,
		SelectFrame,
		DragDrop
	}
	#endregion
}
